package com.travelgroup.utils;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.travelgroup.domain.dto.LocationDTO;
import com.travelgroup.domain.entity.District;
import com.travelgroup.domain.entity.Location;
import com.travelgroup.enums.LeafType;
import com.travelgroup.exception.BusinessException;
import com.travelgroup.service.IDistrictService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

@Component
@Slf4j
public class MapUtil {
    @Value("${app.amap.key}")
    private String apiKey;
    @Resource
    private RestTemplate restTemplate;
    @Value("${app.amap.path}")
    private String SEARCH_LOCATION_URL;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 响应解析器
     * @param <T>
     */
    @FunctionalInterface
    public interface ResponseParser<T> {
        List<T> parse(String jsonResponse) throws JsonProcessingException;
    }

    /**
     * 执行天地图搜索
     * @param params
     * @param parser
     * @return
     * @param <T>
     */
    public <T> List<T> executeSearch(Map<String, Object> params, ResponseParser<T> parser) {
        try {
            // 构造postStr参数
            String postStr = objectMapper.writeValueAsString(params);
            log.info("postStr参数：{}", postStr);

            // 获取天地图api调用结果
            String result = restTemplate.getForObject(SEARCH_LOCATION_URL, String.class, postStr, apiKey);
            return parser.parse(result);
        } catch (Exception e) {
            log.error("调用天地图api失败：{}", e.getMessage());
            throw new BusinessException("调用天地图API失败: " + e.getMessage());
        }
    }

    /**
     * 执行批量搜索
     * @param params
     * @param dataTypes
     * @param batchSize
     * @param parserFactory
     * @return
     * @param <T>
     */
    public <T> List<T> executeBatchSearch(Map<String, Object> params, List<String> dataTypes,
                                          int batchSize, Function<String, ResponseParser<T>> parserFactory) {
        List<T> result = new ArrayList<>();

        for (int i = 0; i < dataTypes.size(); i += batchSize) {
            int end = Math.min(i + batchSize, dataTypes.size());
            List<String> batchTypes = dataTypes.subList(i, end);

            // 为当前批次创建专用参数副本，避免参数污染
            Map<String, Object> batchParams = new HashMap<>(params);

            // 对当前批次的每个类型单独处理
            for (String type : batchTypes) {
                // 创建当前类型的解析器
                ResponseParser<T> parser = parserFactory.apply(type);
                batchParams.put("dataTypes", type);

                // 执行搜索
                List<T> batchResult = executeSearch(batchParams, parser);
                result.addAll(batchResult);

                // 添加短暂延迟，避免API限制
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.warn("批量搜索被中断");
                }
            }
        }

        return result;
    }

    /**
     * 构建搜索参数
     * @param current
     * @param size
     * @param queryType
     * @param searchDTO
     * @return
     */
    public Map<String, Object> buildSearchParams(Integer current, Integer size,
                                                 Integer queryType, LocationDTO searchDTO) {
        Map<String, Object> params = new HashMap<>();
        params.put("queryType", queryType);

        if (StrUtil.isNotBlank(searchDTO.getCityCode())) {
            params.put("specify", searchDTO.getCityCode());
        } else if (searchDTO.getLatitude() != null && searchDTO.getLongitude() != null) {
            double[] bounds = calculateBounds(searchDTO.getLongitude(), searchDTO.getLatitude(),
                    searchDTO.getRadius() != null ? searchDTO.getRadius() : 5000);
            params.put("mapBound", String.format("%f,%f,%f,%f",
                    bounds[0], bounds[1], bounds[2], bounds[3]));
        }

        if (StrUtil.isNotBlank(searchDTO.getKeyword())) {
            params.put("keyWord", searchDTO.getKeyword());
        }

        if (searchDTO.getType() != null && StrUtil.isNotBlank(searchDTO.getType())) {
            params.put("dataTypes", searchDTO.getType());
        }

        // 设置分页
        params.put("start", (current - 1) * size);
        params.put("count", size);

        log.info("搜索参数: {}", params);
        return params;
    }

    /**
     * 行政区划搜索解析器
     * @param parentCode
     * @param leafLevel
     * @param districtService
     * @return
     */
    public ResponseParser<District> createDistrictParser(String parentCode, int leafLevel, IDistrictService districtService) {
        // 解析JSON数据
        return jsonResponse -> {
            JsonNode rootNode = objectMapper.readTree(jsonResponse);
            JsonNode statisticsNode = rootNode.path("statistics");
            JsonNode cityNode = statisticsNode.path("allAdmins");

            List<District> districtList = new ArrayList<>();
            for (JsonNode city : cityNode) {
                District district = new District();
                district.setName(city.get("adminName").asText());

                // 检查是否已存在
                if (districtService.lambdaQuery().eq(District::getName, district.getName()).exists()) {
                    continue;
                }

                // 获取城市代码等信息
                district.setCode(city.get("adminCode").asText());
                district.setParentCode(parentCode);
                district.setLeaf(LeafType.valueOf(String.valueOf(leafLevel + 1)));

                // 获取经纬度
                String lonlat = city.get("lonlat").asText();
                String[] lonlats = lonlat.split(",");
                district.setLongitude(Double.valueOf(lonlats[0]));
                district.setLatitude(Double.valueOf(lonlats[1]));

                districtList.add(district);
            }

            return districtList;
        };
    }

    /**
     * 创建地点解析器
     * @param cityCode
     * @param currentType
     * @return
     */
    public ResponseParser<Location> createLocationParser(String cityCode, String currentType) {
        // 解析JSON数据
        return jsonResponse -> {
            JsonNode rootNode = objectMapper.readTree(jsonResponse);
            List<Location> result = new ArrayList<>();

            // 解析每个POI点
            JsonNode typeNode = rootNode.path("pois");
            if (typeNode == null) throw new BusinessException("API调用解析失败");
            for (JsonNode poiNode : typeNode) {
                // 获取POI的类型
                if (poiNode.isMissingNode()) {
                    continue;
                }

                // 设置地名地址等信息
                Location location = new Location();
                location.setName(poiNode.path("name").asText());
                location.setAddress(poiNode.path("address").asText());
                location.setCityCode(cityCode);
                location.setType(currentType);

                // 根据是否有地点电话进行设置
                JsonNode phoneNode = poiNode.path("phone");
                if (!phoneNode.isMissingNode()) {
                    location.setTelephone(phoneNode.asText());
                }

                // 解析坐标
                JsonNode locationNode = poiNode.path("location");
                if (!locationNode.isMissingNode()) {
                    location.setLongitude(locationNode.path("lon").asDouble());
                    location.setLatitude(locationNode.path("lat").asDouble());
                } else {
                    // 备用解析方式：尝试解析lonlat字段
                    JsonNode lonlatNode = poiNode.path("lonlat");
                    if (!lonlatNode.isMissingNode()) {
                        String lonlat = lonlatNode.asText();
                        String[] lonlats = lonlat.split(",");
                        if (lonlats.length >= 2) {
                            location.setLongitude(Double.valueOf(lonlats[0]));
                            location.setLatitude(Double.valueOf(lonlats[1]));
                        }
                    }
                }

                result.add(location);
            }

            return result;
        };
    }

    /**
     * 计算经纬度
     * @param longitude
     * @param latitude
     * @param radius
     * @return
     */
    private double[] calculateBounds(Double longitude, Double latitude, int radius) {
        // 地球半径（米）
        double earthRadius = 6371000;

        // 计算经度偏移量
        double deltaLng = Math.toDegrees(radius / earthRadius / Math.cos(Math.toRadians(latitude)));

        // 计算纬度偏移量
        double deltaLat = Math.toDegrees(radius / earthRadius);

        return new double[]{
                longitude - deltaLng, // 最小经度
                latitude - deltaLat, // 最小纬度
                longitude + deltaLng, // 最大经度
                latitude + deltaLat  // 最大纬度
        };
    }
}
